package org.elkastud.model;

import java.security.InvalidParameterException;

/**
 * This class provides an abstraction for DNA Sequence.
 * Constructs sequence from String object.
 * Uses alphabet defined in Nucleobase.ALPHABET to validate passed string.
 *
 * @author Jakub Skierbiszewski
 */
public class DNASequence implements Iterable<Nucleobase>
{
	/** 
	 * DNA Sequence. Each character is validated with Nucleobase.ALPHABET
	 * each time object is being constructed.
	 */
	private String mSequence;

	/** Array of nucleobases, enables fast random access */
	private Nucleobase mNucleobaseArray[];

	/**
	 * Iterator for DNASequence, enables usage of for-each loop.
	 * for(Nucleobase b: dnaSequence) b.getNucleobaseCode();
	 */
	public class Iterator implements java.util.Iterator<Nucleobase>
	{
		/** Current element reference - index of nucleobase in nucleobase array */
		private int current = 0;

		/** @return true if sequence has next element */
		public boolean hasNext()
		{
			if(current<length()-2)
				return true;
			else
				return false;
		}

		/** @return next nucleobase */
		public Nucleobase next()
		{
			return getAt(++current);
		}

		/** Method is not supported in this implementation */
		public void remove()
		{
			throw new UnsupportedOperationException("Operation not supported.");
		}
	}

	/**
	 * Constructs DNA Sequence from String representation.
	 * Checks passed char validity with Nucleobase.ALPHABET
	 * @param nucleobaseCode
	 * @throws InvalidParameterException when nucleobaseCode is not valid
	 */
	public DNASequence(String inSequence) throws InvalidParameterException
	{
		//Validate sequence
		if(!validate(inSequence))
			throw new InvalidParameterException();

		this.mNucleobaseArray = new Nucleobase[inSequence.length()];
		this.mSequence = inSequence;
	}

	/**
	 * Returns nucleobase at index
	 * @param index of nucleobase in sequence
	 * @return nucleobase
	 */
	public Nucleobase getAt(int index)
	{
		if(mNucleobaseArray[index]==null)
			mNucleobaseArray[index] =  new Nucleobase(mSequence.charAt(index));
		
		return mNucleobaseArray[index];
	}

	/**
	 * Iterator interface for iterating through DNA Sequence
	 * @return iterator pointing first element
	 */
	public java.util.Iterator<Nucleobase> iterator()
	{
		return new Iterator();
	}

	/** @return sequence length */
	public int length()
	{
		return mSequence.length();
	}

	@Override
	public String toString()
	{
		return mSequence;
	}

	/**
	 * Validates each char of passed sequence with Nucleobase.ALPHABET
	 * @param sequence to validate
	 * @return	true - when sequence contains only characters from Nucleobase.ALPHABET
	 *			false - when sequence contains characters not definedi in Nucleobase.ALPHABET
	 */
	private static boolean validate(String sequence)
	{
		return sequence.matches("["+Nucleobase.ALPHABET+"]*");
	}
}
